package com.dsunsoft.rtu.netty;

import com.dsunsoft.rtu.common.constant.CommonConstants;
import com.dsunsoft.rtu.common.util.CommonUtils;
import com.dsunsoft.rtu.common.util.SpringContextHolder;
import com.dsunsoft.rtu.core.RabbitMqProvider;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.SocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;

@Slf4j
public class NettyServerHandler extends SimpleChannelInboundHandler<byte[]> {

    private final RabbitMqProvider rabbitMqProvider = SpringContextHolder.getBean(RabbitMqProvider.class);

    /**
     * 表示连接建立 第一个被执行
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端建立链接：{}", ctx.channel().remoteAddress());
    }

    /**
     * 断开连接
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端断开链接：{}", ctx.channel().remoteAddress());
    }

    /**
     * 标识channel处于非活动状态
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        NettyChannelMap.remove((SocketChannel) ctx.channel());
    }

    /**
     * 服务端 接收到 客户端 发的数据
     *
     * @param context
     * @param data
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext context, byte[] data) throws Exception {
        // 客户端向服务端发送数据（获取客户端IP和端口、相关数据）
        SocketChannel socketChannel = (SocketChannel) context.channel();
        String remoteAddress = socketChannel.remoteAddress().toString();
        String hexData = CommonUtils.bytesToHexString(data);
        log.info("收到客户端消息: {}, 报文长度: {}, 16进制: {}", remoteAddress, data.length, hexData);

        if (StringUtils.isNotBlank(hexData)) {
            //  报头    设备ID  数据长度  设备类型
            //  97 96  00 01   00 0C   07
            // 降雨   报文:  97 96 00 01 00 0C 07 03 08 00 11 00 25 00 38 00 80 (00 或 01) 摄像机状态
            // 水位   报文:  97 96 00 0D 00 09 17 03 06 01 02 03 04 05 06
            if (hexData.startsWith(CommonConstants.TCP_REQUEST_DATA) && hexData.length() >= 14) {
                // 发送消息队列处理
                rabbitMqProvider.send(CommonConstants.TASK_QUEUE, hexData);
            } else if (hexData.startsWith(CommonConstants.TCP_REQUEST_HEARTBEAT)) {
                // 心跳 报文: 10 00 00 01 00 09 68 65 61 72 74 62 65 61 74
                if (hexData.length() >= 8) {
                    Integer deviceId = Integer.parseInt(hexData.substring(4, 8), 16);
                    NettyChannelMap.add(deviceId, socketChannel);
                    NettyHeartbeatMap.add(deviceId, new Date());
                }
            }
            // 无需返回数据
            // byte[] resMsg = "ok".getBytes(StandardCharsets.US_ASCII);
            // socketChannel.writeAndFlush(resMsg);
        }
    }

    /**
     * 当出现 Throwable 对象才会被调用
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("exceptionCaught: ", cause);
        ctx.close();
    }
}
